#ifndef __TUNERBASE_STUFF
#define __TUNERBASE_STUFF

/*
 *   This file is part of ed_pvr.
 *
 *   ed_pvr is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   ed_pvr is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with ed_pvr.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifdef __cplusplus
    extern "C" {
#endif

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <pthread.h>
#include <stdarg.h>
#include <arpa/inet.h>
#include "timers.h"
#include "utils.h"
#include "bitstream.h"
#include "mpegts.h"
#include "mpegts_io.h"


#ifdef USE_WWIN
static const char *TUNER_READ_STATUS_STR[5] =
{
	"Error",
	"Idle",
	"Tuning",
	"Tuned",
	"Reading",
};

static const char *TUNER_WRITE_STATUS_STR[8] =
{
	"Error",
	"Init..",
	"Wait for CMD conn.",
	"Send special packet",
	"Waiting for packets",
	"Writing",
	"Paused",
	"Done",
};

#endif

#ifdef USE_GLIB
#include <glib.h>

#endif
// Defines

#define CONNECTION_MAX_THREADS				25


#define MAX_CONNECT_COUNT					16
#define MAX_VALID_PIDS						10
#define MAX_VALID_URLS						5
#define MAX_DEVNAME_SIZE					1024

#define TUNE_TYPE_CETON						0x01
#define TUNE_TYPE_HDHR						0x02
#define TUNE_TYPE_RESTREAM					0x03
#define TUNE_TYPE_DVB_ATSC					0x04
#define TUNE_TYPE_HLS						0x05

#define MAX_SEGMENT_COUNT					20
#define MAX_SEGMENT_SIZE					100000000

#define TUNER_STREAM_TYPE_HTTP				0x01
#define TUNER_STREAM_TYPE_PROTOCOL			0x02
#define TUNER_STREAM_TYPE_RECORDING			0x03
#define TUNER_STREAM_TYPE_SCAN				0x04

#define TUNER_EXIT_MSG						0xE0

#define TUNER_TUNE_ERROR_UNKNOWN			0x01
#define TUNER_TUNE_ERROR_NOCHAN				0x02

#define TUNER_CHANNEL_PID_AUDIO				0x01
#define TUNER_CHANNEL_PID_VIDEO				0x02
#define TUNER_MAX_DVB_HANDLES				16

#define	TUNER_READ_STATUS_IDLE					0x01
#define	TUNER_READ_STATUS_TUNING				0x02
#define	TUNER_READ_STATUS_TUNED					0x03
#define	TUNER_READ_STATUS_READING				0x04

#define	TUNER_WRITE_STATUS_INIT					0x01
#define	TUNER_WRITE_STATUS_WAIT_CMD_SOCK		0x02
#define	TUNER_WRITE_STATUS_SEND_SPECIAL			0x03
#define	TUNER_WRITE_STATUS_WAIT_PACKETS			0x04
#define	TUNER_WRITE_STATUS_WRITING				0x05
#define	TUNER_WRITE_STATUS_PAUSED				0x06
#define	TUNER_WRITE_STATUS_DONE					0x07

#define TUNER_CHANNEL_FILTER_NONE				0x00
#define TUNER_CHANNEL_FILTER_INCLUDE			0x01
#define TUNER_CHANNEL_FILTER_EXCLUDE			0x02

#define TUNER_STREAM_DETECT_COUNT				5
#define TUNER_MAX_STREAMS						20

#define DEVICE_THREAD_STATE_DIE					0
#define DEVICE_THREAD_STATE_SLEEP				1
#define DEVICE_THREAD_STATE_WORK				2

#define DEVICE_READ_NOERROR						0
#define DEVICE_READ_ERROR						1
#define DEVICE_READ_NODATA						2


static const uint8_t SPECIAL_NULL_PACKET[188] =
{
	0x47, 0x1F, 0xFF, 0xFD, 0xFC, 0xFB, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x24,
};

static const uint8_t SPECIAL_NULL_PACKET_SIGNAL_INFO[188] =
{
	0x47, 0x1F, 0xFF, 0xFD, 0xFC, 0xFB, 0xFA, 0x00, 0x00, 0x01, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
};

static const uint8_t SPECIAL_NULL_PACKET_STREAM_CHANGED[188] =
{
	0x47, 0x1F, 0xFF, 0xFD, 0xFC, 0xFB, 0xFA, 0x00, 0x00, 0x02, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xAA, 0xBB, 0xCC, 0xDD,
};


static const uint8_t SPECIAL_NULL_STREAM_INFO[188] =
{
	0x47, 0x1F, 0xFF, 0xFD, 0xFC, 0xFA, 0xFA, 0x00, 0xFC, 0x02, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
};

static const uint8_t SPECIAL_NULL_STREAM_END[188] =
{
	0x47, 0x1F, 0xFF, 0xFD, 0xFC, 0xFA, 0xFA, 0x00, 0xFC, 0x02, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0xFF, 0xFF, 0x1E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xEE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xD0, 0xFF, 0xFF, 0x1C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
};

static const uint8_t NULL_PACKET[188] =
{
	0x47, 0x1F, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,


	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
};



// End of Defines

// Structs
struct tuner_stream_packet_struct
{
	uint8_t data[TS_PACKET_SIZE];
	uint8_t data_size;
};
typedef struct tuner_stream_packet_struct TUNER_STREAM_PACKET_STRUCT;


struct tuner_stream_struct
{
	uint16_t 	pid;
	uint8_t 	type;
	uint8_t 	processed;
	uint32_t 	bitrate;
	uint32_t	frame_size;

	uint32_t	width;
	uint32_t 	height;
	uint32_t 	fps;
	uint32_t 	aspect;

	uint32_t 	channels;
	uint32_t 	samplerate;
	uint8_t		iso639_lang[4];
	uint8_t		is_last;

};
typedef struct tuner_stream_struct TUNER_STREAM_STRUCT;

struct tuner_channel_struct
{
	char name[MAX_DEVNAME_SIZE];
	char info[MAX_DEVNAME_SIZE];
	char xmltv_id[MAX_DEVNAME_SIZE];
	char icon_url[MAX_DEVNAME_SIZE];

	uint32_t virtual_channel;
	uint64_t program_num;

	uint32_t pgm_pmt;
	uint16_t sid;
	uint8_t modulation_type;
//	uint64_t valid_count;
	uint8_t pid_count;
	uint16_t pids[MAX_VALID_PIDS];
	uint8_t pids_type[MAX_VALID_PIDS];

	uint8_t url_count;
	char *urls[MAX_VALID_URLS];

	void *prot_params;
	char *url_params;

	struct tuner_channel_struct *next;
};
typedef struct tuner_channel_struct TUNER_CHANNEL_STRUCT;


struct tuner_writepass_struct
{
	struct tuner_struct *tuner;
	MPEGTS_IO_READER_STRUCT * reader;
	char ip_addr[INET_ADDRSTRLEN];
	uint8_t die;
	uint8_t misc;
	uint8_t record_status;
	int write_status;
	int bad_cmd_count;
	int client_socket;
	int command_socket;
	int thread_index;
	uint32_t packets_to_buffer;
	uint8_t reader_type;
	uint8_t stream_type;
	uint8_t seeked;
	uint64_t time_pos;
	uint8_t stop_writing;
	uint64_t last_seek_time;
	uint64_t last_keepalive;

	pthread_t write_thread;

	pthread_t command_thread;
	pthread_mutex_t command_mutex;
	pthread_mutex_t read_write_mutex;

	uint64_t bytes_written;
//	time_t start_write_time;
	int64_t start_write_time;
};
typedef struct tuner_writepass_struct TUNER_WRITEPASS_STRUCT;


struct tuner_initpass_struct
{
	uint64_t start_pos;
	uint64_t channel_num;
	int32_t	r_state;
	uint32_t epg_days;
	uint32_t id;
	uint8_t type;
	uint8_t cmd;
	int sock;
	struct device_struct * device;
	uint8_t *dataptr;
	uint32_t datasz;
	char ip_addr[INET_ADDRSTRLEN];
	char *url_params;
	void *tuner_params;
	void *extra_data[10];
};
typedef struct tuner_initpass_struct TUNER_INITPASS_STRUCT;


struct tuner_struct
{
	char frontend[MAX_DEVNAME_SIZE];
	char demux[MAX_DEVNAME_SIZE];
	char dvr[MAX_DEVNAME_SIZE];

	uint8_t tuning;
	uint16_t signal_status;
	uint16_t signal_noise_ratio;
	uint16_t signal_strength;
	//time_t signal_last_update;
	int64_t signal_last_update;

	uint8_t pid_msg;
	void *extra_data[10];
	void *screen_var;

	char *segment_dir;
	char *base_filename;

	pthread_t read_thread;
	pthread_t process_thread;

	pthread_mutex_t init_mutex;
	pthread_mutex_t write_thread_init_lock;
	uint8_t write_thread_count;

	void *parent;
	char name[MAX_DEVNAME_SIZE];
	uint8_t id;
	int id_offset;
	int thread_id;

	int devhandle;
	int devhandles[TUNER_MAX_DVB_HANDLES];
	FILE *filehandle;

	int	read_status;
	uint64_t bytes_read;
	int64_t start_read_time;
//	time_t start_read_time;
	uint32_t read_block_time;
	uint32_t read_thread_sleep_time;

	uint32_t packets_to_buffer;
	size_t read_size;
	uint8_t *read_data_ptr;
	uint8_t alive;
	int16_t writing;

	uint64_t tuned_channel;
	uint64_t tuned_freq;
	uint64_t packet_count;
	uint64_t pat_count;
	uint64_t pmt_count;
	uint8_t fix_stream;
	uint8_t haz_data;
	uint8_t type;
	uint64_t pts_dts_offset;
	uint64_t pts_offset;
	uint64_t dts_offset;
	uint64_t pgm_num;
	uint16_t pmt_pid;
	uint16_t video_pid;
	uint8_t video_es_type;
	uint8_t audio_es_type;
	uint8_t valid_count;
	uint16_t valid_pids[MAX_VALID_PIDS];
	uint16_t valid_pids_type[MAX_VALID_PIDS];

	uint8_t reset_valid_pids;
//	uint8_t reset_video_pids;
//	uint8_t reset_audio_pids;
	uint8_t send_stream_change;

	uint32_t mpegts_fileunit_cachesize;
	uint32_t mpegts_fileunit_maxsize;
	uint32_t mpegts_fileunit_maxlife;


	uint8_t streams_count;
	TUNER_STREAM_STRUCT streams[TUNER_MAX_STREAMS];
	MPEGTS_IO_STRUCT *mpegts_io;
	MPEGTS_IO_INIT_ARGS_STRUCT io_opts;
	MPEGTS_PARSE_STRUCT ts_parser;
#ifdef USE_GLIB
	GAsyncQueue * process_buffer_queue;
	GAsyncQueue * memlist_queue;
	GThreadPool * write_thread_pool;
#endif

	MPEGTS_PAT_PROGRAM_STRUCT *(*cb_process_pat)(MPEGTS_PAT *, TUNER_CHANNEL_STRUCT *);
	uint8_t (*cb_process_pmt)(MPEGTS_PMT *);
	uint8_t (*cb_write_data)(struct tuner_struct *);
	uint8_t (*cb_write_ended)(struct tuner_struct *);
	uint8_t (*cb_close_data)(struct tuner_struct *);
	uint8_t (*cb_read_data)(struct tuner_struct *);
	uint8_t (*cb_update_tuner_stats)(struct tuner_struct *);
//	int (*cb_tune_channel)(struct tuner_struct *, uint32_t channel);
	int (*cb_tune_channel)(struct tuner_struct *, TUNER_INITPASS_STRUCT *);

	void (*cb_gui_tuner_read_status)(struct tuner_struct *);
	void (*cb_gui_tuner_write_status)(struct tuner_writepass_struct *);

	struct tuner_struct *next;
};
typedef struct tuner_struct TUNER_STRUCT;

struct tuner_channel_filter_struct
{
	uint8_t type;
	char *filename;
	int64_t mtime;
//	time_t mtime;
#ifdef USE_GLIB
	GSList *filter_glist;
#endif
};
typedef struct tuner_channel_filter_struct TUNER_CHANNEL_FILTER_STRUCT;

struct device_conn_struct
{
	int id;
	pthread_t tid;
	int status;
	int socket;
	struct device_struct *device;
	char addr_buf[INET_ADDRSTRLEN];
};
typedef struct device_conn_struct DEVICE_CONN_STRUCT;

struct device_struct
{
	void *parent;
//	char *xmltv_filename;
	char name[MAX_DEVNAME_SIZE];
	uint8_t connect_wait;
	uint8_t stream_only;
	uint8_t type;
	uint8_t listening;
	int listen_socket;
	int id;
	uint8_t max_tuners;
	uint8_t tuner_count;

	uint16_t bind_port;
	char *bind_ip;
	uint32_t channel_count;

	pthread_t listen_thread;
	pthread_mutex_t tunerlock;
	pthread_mutex_t thread_init_mutex;
	pthread_mutex_t process_cmd_mutex;

//	DEVICE_CONN_STRUCT conn_pool[CONNECTION_MAX_THREADS];

	uint32_t thread_init_count;

	TUNER_CHANNEL_FILTER_STRUCT * channel_filter;
	TUNER_STRUCT *first_tuner;
	TUNER_STRUCT *current_tuner;

	TUNER_CHANNEL_STRUCT *first_channel_list;
	TUNER_CHANNEL_STRUCT *current_channel_list;

	UTILS_LOG_STRUCT *log;

#ifdef USE_GLIB
	GThreadPool * glib_conn_thread_pool;
#endif

	int (*cb_wait)(struct tuner_initpass_struct *);
	int	(*cb_chan_count)(struct tuner_initpass_struct *);
	int	(*cb_chan_list)(struct tuner_initpass_struct *);
	int	(*cb_epg_chan)(struct tuner_initpass_struct *);
	int	(*cb_reload_epg)(struct tuner_initpass_struct *);
	int (*cb_rec_play)(struct tuner_initpass_struct *);
	int (*cb_rec_del)(struct tuner_initpass_struct *);
	int (*cb_rec_stop)(struct tuner_initpass_struct *);
	int (*cb_rec_list)(struct tuner_initpass_struct *);
	int (*cb_rec_count)(struct tuner_initpass_struct *);
	int (*cb_rec_seqnum)(struct tuner_initpass_struct *);

	int (*cb_timer_add)(struct tuner_initpass_struct *);
	int (*cb_timer_del)(struct tuner_initpass_struct *);
	int (*cb_timer_list)(struct tuner_initpass_struct *);
	int (*cb_timer_count)(struct tuner_initpass_struct *);
	int (*cb_timer_seqnum)(struct tuner_initpass_struct *);

	int (*cb_gui_incoming_parse)(char *, uint8_t, uint8_t);
	int (*cb_dev_printf)(struct device_struct*, const char *, va_list);
};
typedef struct device_struct DEVICE_STRUCT;

struct device_init_args_struct
{
	uint8_t filter_type;
	char *filter_file;
	char *dvb_default_path;

	char *segment_dir;
	char *base_filename;

	char *bind_ip;
	uint16_t bind_port;

	uint32_t max_segment_size;
	uint32_t max_segment_life;
	uint32_t max_cachesize;

	char *zap_lineup;
	char *zap_zip;
	char *zap_cache_dir;

	char *recording_dir;
	char *timer_file;

	char *channels_file;
	char *config_file;
	char *session_key_file;
	uint32_t channel_num_offset;

	char *device_path;

	char *atsc_id;
	char *device_name;
	uint16_t max_tuners;

	char *xmltv_file;
	uint32_t timer_post_pad;
	uint32_t timer_pre_pad;
};
typedef struct device_init_args_struct DEVICE_INIT_ARGS_STRUCT;

// End of Structs

#ifdef USE_GLIB

// Function Declarations
DEVICE_STRUCT *device_init(char *, uint16_t);

TUNER_CHANNEL_STRUCT * device_channel_get_struct(DEVICE_STRUCT *, uint64_t, uint64_t);
void device_channel_reset_data(DEVICE_STRUCT *, uint64_t, uint64_t);
void device_channel_print_all(DEVICE_STRUCT *);
void device_channel_print(TUNER_CHANNEL_STRUCT *);
void device_channel_clear(DEVICE_STRUCT *);
void device_channel_add_iconurl(DEVICE_STRUCT *, uint64_t, uint64_t, char *);
void device_channel_add_url(DEVICE_STRUCT *, uint64_t, uint64_t, char *);
void device_channel_add_xmltv_id(DEVICE_STRUCT *, uint64_t, uint64_t, char *);
void device_channel_add_pid(DEVICE_STRUCT *, uint64_t, uint64_t, uint16_t, uint8_t);
void device_channel_add_name(DEVICE_STRUCT *, uint64_t, uint64_t, char *);
void device_channel_add_sid(DEVICE_STRUCT *, uint64_t, uint64_t, uint16_t);
void device_channel_set_modulation(DEVICE_STRUCT *, uint64_t, uint64_t, uint8_t);
void device_channel_add_info(DEVICE_STRUCT *dev, uint64_t, uint64_t, char *);
uint8_t device_channel_get_pid_type(TUNER_STRUCT *, uint16_t);

TUNER_CHANNEL_STRUCT * device_channel_add(DEVICE_STRUCT *, uint64_t, uint64_t);
uint8_t device_channel_pid_valid(TUNER_STRUCT *, uint16_t);


TUNER_STRUCT *device_tuner_init(uint8_t);
void device_tuner_add(DEVICE_STRUCT *, TUNER_STRUCT *);
TUNER_STRUCT * device_tuner_find(DEVICE_STRUCT *, int);
void device_tuner_destroy(TUNER_STRUCT *);
void device_destroy(DEVICE_STRUCT *);
int32_t device_channel_get_count(DEVICE_STRUCT *);
int device_reload_channel_filter(DEVICE_STRUCT *);
TUNER_STREAM_STRUCT * device_tuner_clear_streams(TUNER_STRUCT *);

#endif

#ifdef __cplusplus
    }
#endif

#endif
